package com.gitee.qdbp.base.orm.mybatis.converter;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

/**
 * 4字节字符替换为URL编码字符串, 否则保存到数据库报错<br>
 * 用于处理emoji表情
 *
 * @author zhaohuihua
 * @version 170905
 * @since V3.2.0
 */
public class Utf8mb4TextHandler extends BaseTypeHandler<String> {

    private static final String ENCODING = "UTF-8";

    // \\uD800\\uDC00-\\uDBFF\\uDFFF\\uD800-\\uDFFF
    private static final Pattern UTF8MB4 = Pattern.compile("[\\uD800\\uDC00-\\uDBFF\\uDFFF]");

    public Utf8mb4TextHandler(Class<?> type) {
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
            throws SQLException {
        ps.setString(i, encode(parameter));
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        if (rs.wasNull()) {
            return null;
        } else {
            return decode(value);
        }
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String value = rs.getString(columnIndex);
        if (rs.wasNull()) {
            return null;
        } else {
            return decode(value);
        }
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        if (cs.wasNull()) {
            return null;
        } else {
            return decode(value);
        }
    }

    private String encode(String text) {
        Matcher matcher = UTF8MB4.matcher(text);
        int index = 0;
        StringBuilder buffer = new StringBuilder();
        while (matcher.find()) {
            buffer.append(text.substring(index, matcher.start()));
            String string = matcher.group(0);
            try {
                buffer.append(URLEncoder.encode(string, ENCODING));
            } catch (UnsupportedEncodingException e) {
                buffer.append(string);
            }
            index = matcher.end();
        }
        buffer.append(text.substring(index));
        return buffer.toString();
    }

    private String decode(String value) {
        try {
            return URLDecoder.decode(value, ENCODING);
        } catch (UnsupportedEncodingException e) {
            return value;
        }
    }
}
